﻿#include <xy/ais/arrow.h>
#include <xy/ais/builder.h>
#include <xy/ais/curve.h>
#include <xy/ais/point.h>
#include <xy/ais/surface.h>

namespace xy
{

namespace ais
{

using namespace xy::geom;

std::shared_ptr<object> builder::create_point(const vec3 &point)
{
    vec3 x(1.0, 0.0, 0.0);
    vec3 y(0.0, 1.0, 0.0);
    vec3 z(0.0, 0.0, 1.0);

    return create_point(point, {x, y, z});
}

std::shared_ptr<object> builder::create_point(const vec3 &point, const std::vector<vec3> &axis)
{
    auto pPoint = std::make_shared<vec3>(point);
    auto aisPoint = std::make_shared<ais::point>(pPoint);

    // 必须在构造时立即创建子节点，防止初始化消息无法传递给子节点
    std::vector<std::shared_ptr<arrow>> arrows;
    for (const auto &v : axis)
    {
        auto vec = std::make_shared<arrow>(aisPoint->pnt(), std::make_shared<vec3>(v));
        arrows.push_back(vec);
    }

    // 隐藏坐标轴
    auto msg = std::make_shared<msg_visible>();
    msg->show = false;
    for (auto &vec : arrows)
        vec->handle_msg(msg);

    for (auto &vec : arrows)
        aisPoint->add_child(vec);

    return aisPoint;
}

std::shared_ptr<object> builder::create_vector(const vec3 &start, const vec3 &end)
{
    auto pStart = std::make_shared<vec3>(start);
    auto pEnd = std::make_shared<vec3>(end);
    return std::make_shared<arrow>(pStart, pEnd);
}

std::shared_ptr<object> builder::create_curve(std::shared_ptr<bspline_curve<3>> curve)
{
    // 用于隐藏辅助点
    auto msg = std::make_shared<msg_visible>();
    msg->show = false;

    auto n = curve->pole_num();
    auto aisCurve = std::make_shared<ais::curve>(curve);
    auto aisAuxCurve = std::make_shared<curve_auxiliary>();
    for (std::size_t i = 0; i < n; ++i)
    {
        auto getter = [curve, i]() { return curve->pole(i); };
        auto setter = [curve, i](const vec3 &p) { curve->set_pole(p, i); };
        auto aisPoint = std::make_shared<point_auxiliary>(getter, setter);
        aisPoint->handle_msg(msg);
        aisCurve->add_child(aisPoint);
        aisAuxCurve->add_point(aisPoint);
    }

    aisAuxCurve->handle_msg(msg);
    aisCurve->add_child(aisAuxCurve);

    return aisCurve;
}

std::shared_ptr<object> builder::create_surface(std::shared_ptr<bspline_surface<3>> surface)
{
    // 用于隐藏辅助点
    auto msg = std::make_shared<msg_visible>();
    msg->show = false;

    auto nu = surface->pole_num(0);
    auto nv = surface->pole_num(1);
    auto aisSurface = std::make_shared<ais::surface>(surface);

    // 不要使用 (nv, std::make_shared<curve_auxiliary>())，这会创建 nv 个相同的 curve_auxiliary 实例
    std::vector<std::shared_ptr<curve_auxiliary>> vCurves(nv);
    for (std::size_t v = 0; v < nv; ++v)
    {
        auto aisAuxVCurve = std::make_shared<curve_auxiliary>();
        vCurves[v] = aisAuxVCurve;
    }

    for (std::size_t u = 0; u < nu; ++u)
    {
        auto aisAuxUCurve = std::make_shared<curve_auxiliary>();
        for (std::size_t v = 0; v < nv; ++v)
        {
            auto getter = [surface, u, v]() { return surface->pole(u, v); };
            auto setter = [surface, u, v](const vec3 &p) { surface->set_pole(p, u, v); };
            auto aisPoint = std::make_shared<point_auxiliary>(getter, setter);
            aisPoint->handle_msg(msg);
            aisSurface->add_child(aisPoint);
            aisAuxUCurve->add_point(aisPoint);
            vCurves[v]->add_point(aisPoint);
        }

        aisAuxUCurve->handle_msg(msg);
        aisSurface->add_child(aisAuxUCurve);
    }

    for (auto &curve : vCurves)
    {
        curve->handle_msg(msg);
        aisSurface->add_child(curve);
    }

    return aisSurface;
}

} // namespace ais

} // namespace xy
